/*
 * Zirco Browser for Android
 * 
 * Copyright (C) 2010 J. Devauchelle and contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package org.gaeproxy.zirco.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.gaeproxy.R;
import org.gaeproxy.zirco.model.items.BookmarkItem;
import org.gaeproxy.zirco.model.items.HistoryItem;
import org.gaeproxy.zirco.providers.BookmarksProviderWrapper;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.Toast;

/**
 * Application utilities.
 */
public class ApplicationUtils {

	private static String mAdSweepString = null;

	private static String mRawStartPage = null;
	private static String mRawStartPageStyles = null;
	private static String mRawStartPageBookmarks = null;
	private static String mRawStartPageHistory = null;

	private static String mRawStartPageSearch = null;

	private static int mFaviconSize = -1;
	private static int mImageButtonSize = -1;
	private static int mFaviconSizeForBookmarks = -1;

	/**
	 * Check if the SD card is available. Display an alert if not.
	 * 
	 * @param context
	 *            The current context.
	 * @param showMessage
	 *            If true, will display a message for the user.
	 * @return True if the SD card is available, false otherwise.
	 */
	public static boolean checkCardState(Context context, boolean showMessage) {
		// Check to see if we have an SDCard
		String status = Environment.getExternalStorageState();
		if (!status.equals(Environment.MEDIA_MOUNTED)) {

			int messageId;

			// Check to see if the SDCard is busy, same as the music app
			if (status.equals(Environment.MEDIA_SHARED)) {
				messageId = R.string.Commons_SDCardErrorSDUnavailable;
			} else {
				messageId = R.string.Commons_SDCardErrorNoSDMsg;
			}

			if (showMessage) {
				ApplicationUtils.showErrorDialog(context,
						R.string.Commons_SDCardErrorTitle, messageId);
			}

			return false;
		}

		return true;
	}

	/**
	 * Copy a text to the clipboard.
	 * 
	 * @param context
	 *            The current context.
	 * @param text
	 *            The text to copy.
	 * @param toastMessage
	 *            The message to show in a Toast notification. If empty or null,
	 *            does not display notification.
	 */
	public static void copyTextToClipboard(Context context, String text,
			String toastMessage) {
		ClipboardManager clipboard = (ClipboardManager) context
				.getSystemService(Context.CLIPBOARD_SERVICE);
		clipboard.setText(text);

		if ((toastMessage != null) && (toastMessage.length() > 0)) {
			Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
		}
	}

	/**
	 * Load the AdSweep script if necessary.
	 * 
	 * @param context
	 *            The current context.
	 * @return The AdSweep script.
	 */
	public static String getAdSweepString(Context context) {
		if (mAdSweepString == null) {
			InputStream is = context.getResources().openRawResource(
					R.raw.adsweep);
			if (is != null) {
				StringBuilder sb = new StringBuilder();
				String line;

				try {
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(is, "UTF-8"));
					while ((line = reader.readLine()) != null) {
						if ((line.length() > 0) && (!line.startsWith("//"))) {
							sb.append(line).append("\n");
						}
					}
				} catch (IOException e) {
					Log.w("AdSweep",
							"Unable to load AdSweep: " + e.getMessage());
				} finally {
					try {
						is.close();
					} catch (IOException e) {
						Log.w("AdSweep",
								"Unable to load AdSweep: " + e.getMessage());
					}
				}
				mAdSweepString = sb.toString();
			} else {
				mAdSweepString = "";
			}
		}
		return mAdSweepString;
	}

	/**
	 * Get the application version code.
	 * 
	 * @param context
	 *            The current context.
	 * @return The application version code.
	 */
	public static int getApplicationVersionCode(Context context) {

		int result = -1;

		try {

			PackageManager manager = context.getPackageManager();
			PackageInfo info = manager.getPackageInfo(context.getPackageName(),
					0);

			result = info.versionCode;

		} catch (NameNotFoundException e) {
			Log.w("ApplicationUtils",
					"Unable to get application version: " + e.getMessage());
			result = -1;
		}

		return result;
	}

	/**
	 * Build the html result of the most recent bookmarks.
	 * 
	 * @param context
	 *            The current context.
	 * @return The html result of the most recent bookmarks.
	 */
	private static String getBookmarksHtml(Context context) {
		String result = "";
		StringBuilder bookmarksSb = new StringBuilder();

		if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
				Constants.PREFERENCES_START_PAGE_SHOW_BOOKMARKS, true)) {

			int limit;
			try {
				limit = Integer
						.parseInt(PreferenceManager
								.getDefaultSharedPreferences(context)
								.getString(
										Constants.PREFERENCES_START_PAGE_BOOKMARKS_LIMIT,
										"5"));
			} catch (Exception e) {
				limit = 5;
			}

			List<BookmarkItem> results = BookmarksProviderWrapper
					.getStockBookmarksWithLimit(context.getContentResolver(),
							limit);

			for (BookmarkItem item : results) {
				bookmarksSb.append(String.format(
						"<li><a href=\"%s\">%s</a></li>", item.getUrl(),
						item.getTitle()));
			}
		}

		result = String.format(mRawStartPageBookmarks, context.getResources()
				.getString(R.string.StartPage_Bookmarks), bookmarksSb
				.toString());

		return result;
	}

	/**
	 * Load the changelog string.
	 * 
	 * @param context
	 *            The current context.
	 * @return The changelog string.
	 */
	public static String getChangelogString(Context context) {
		return getStringFromRawResource(context, R.raw.changelog);
	}

	/**
	 * Get the required size of the favicon, depending on current screen
	 * density.
	 * 
	 * @param activity
	 *            The current activity.
	 * @return The size of the favicon, in pixels.
	 */
	public static int getFaviconSize(Activity activity) {
		if (mFaviconSize == -1) {
			DisplayMetrics metrics = new DisplayMetrics();
			activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

			switch (metrics.densityDpi) {
			case DisplayMetrics.DENSITY_LOW:
				mFaviconSize = 12;
				break;
			case DisplayMetrics.DENSITY_MEDIUM:
				mFaviconSize = 24;
				break;
			case DisplayMetrics.DENSITY_HIGH:
				mFaviconSize = 32;
				break;
			default:
				mFaviconSize = 24;
			}
		}

		return mFaviconSize;
	}

	/**
	 * Get the required size of the favicon, depending on current screen
	 * density.
	 * 
	 * @param activity
	 *            The current activity.
	 * @return The size of the favicon, in pixels.
	 */
	public static int getFaviconSizeForBookmarks(Activity activity) {
		if (mFaviconSizeForBookmarks == -1) {
			DisplayMetrics metrics = new DisplayMetrics();
			activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

			switch (metrics.densityDpi) {
			case DisplayMetrics.DENSITY_LOW:
				mFaviconSizeForBookmarks = 12;
				break;
			case DisplayMetrics.DENSITY_MEDIUM:
				mFaviconSizeForBookmarks = 16;
				break;
			case DisplayMetrics.DENSITY_HIGH:
				mFaviconSizeForBookmarks = 24;
				break;
			default:
				mFaviconSizeForBookmarks = 16;
			}
		}

		return mFaviconSizeForBookmarks;
	}

	/**
	 * Build the html result of the most recent history.
	 * 
	 * @param context
	 *            The current context.
	 * @return The html result of the most recent history.
	 */
	private static String getHistoryHtml(Context context) {
		String result = "";
		StringBuilder historySb = new StringBuilder();

		if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
				Constants.PREFERENCES_START_PAGE_SHOW_HISTORY, true)) {

			int limit;
			try {
				limit = Integer.parseInt(PreferenceManager
						.getDefaultSharedPreferences(context).getString(
								Constants.PREFERENCES_START_PAGE_HISTORY_LIMIT,
								"5"));
			} catch (Exception e) {
				limit = 5;
			}

			List<HistoryItem> results = BookmarksProviderWrapper
					.getStockHistoryWithLimit(context.getContentResolver(),
							limit);

			for (HistoryItem item : results) {
				historySb.append(String.format(
						"<li><a href=\"%s\">%s</a></li>", item.getUrl(),
						item.getTitle()));
			}
		}

		result = String.format(mRawStartPageHistory, context.getResources()
				.getString(R.string.StartPage_History), historySb.toString());

		return result;
	}

	public static int getImageButtonSize(Activity activity) {
		if (mImageButtonSize == -1) {
			DisplayMetrics metrics = new DisplayMetrics();
			activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

			switch (metrics.densityDpi) {
			case DisplayMetrics.DENSITY_LOW:
				mImageButtonSize = 16;
				break;
			case DisplayMetrics.DENSITY_MEDIUM:
				mImageButtonSize = 32;
				break;
			case DisplayMetrics.DENSITY_HIGH:
				mImageButtonSize = 48;
				break;
			default:
				mImageButtonSize = 32;
			}
		}

		return mImageButtonSize;
	}

	/**
	 * Load the start page html.
	 * 
	 * @param context
	 *            The current context.
	 * @return The start page html.
	 */
	public static String getStartPage(Context context) {

		if (mRawStartPage == null) {

			mRawStartPage = getStringFromRawResource(context, R.raw.start);
			mRawStartPageStyles = getStringFromRawResource(context,
					R.raw.start_style);
			mRawStartPageBookmarks = getStringFromRawResource(context,
					R.raw.start_bookmarks);
			mRawStartPageHistory = getStringFromRawResource(context,
					R.raw.start_history);

			mRawStartPageSearch = getStringFromRawResource(context,
					R.raw.start_search);
		}

		String result = mRawStartPage;

		String bookmarksHtml = getBookmarksHtml(context);
		String historyHtml = getHistoryHtml(context);

		String searchHtml = "";
		if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
				Constants.PREFERENCES_START_PAGE_SHOW_SEARCH, false)) {
			searchHtml = String
					.format(mRawStartPageSearch,
							context.getResources().getString(
									R.string.StartPage_Search),
							context.getResources().getString(
									R.string.StartPage_SearchButton));
		}

		String bodyHtml = searchHtml + bookmarksHtml + historyHtml;

		result = String
				.format(mRawStartPage, mRawStartPageStyles, context
						.getResources().getString(R.string.StartPage_Welcome),
						bodyHtml);

		return result;
	}

	/**
	 * Load a raw string resource.
	 * 
	 * @param context
	 *            The current context.
	 * @param resourceId
	 *            The resource id.
	 * @return The loaded string.
	 */
	private static String getStringFromRawResource(Context context,
			int resourceId) {
		String result = null;

		InputStream is = context.getResources().openRawResource(resourceId);
		if (is != null) {
			StringBuilder sb = new StringBuilder();
			String line;

			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(is, "UTF-8"));
				while ((line = reader.readLine()) != null) {
					sb.append(line).append("\n");
				}
			} catch (IOException e) {
				Log.w("ApplicationUtils", String.format(
						"Unable to load resource %s: %s", resourceId,
						e.getMessage()));
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					Log.w("ApplicationUtils", String.format(
							"Unable to load resource %s: %s", resourceId,
							e.getMessage()));
				}
			}
			result = sb.toString();
		} else {
			result = "";
		}

		return result;
	}

	public static String getWeaveAuthToken(Context context) {
		String server = PreferenceManager.getDefaultSharedPreferences(context)
				.getString(Constants.PREFERENCE_WEAVE_SERVER,
						Constants.WEAVE_DEFAULT_SERVER);
		String userName = PreferenceManager
				.getDefaultSharedPreferences(context).getString(
						Constants.PREFERENCE_WEAVE_USERNAME, null);
		String password = PreferenceManager
				.getDefaultSharedPreferences(context).getString(
						Constants.PREFERENCE_WEAVE_PASSWORD, null);
		String key = PreferenceManager.getDefaultSharedPreferences(context)
				.getString(Constants.PREFERENCE_WEAVE_KEY, null);

		boolean ok = (server != null) && (server.length() > 0)
				&& (UrlUtils.isUrl(server)) && (userName != null)
				&& (userName.length() > 0) && (password != null)
				&& (password.length() > 0) && (key != null)
				&& (key.length() > 0);

		if (ok) {
			return String.format(Constants.WEAVE_AUTH_TOKEN_SCHEME, key,
					password, userName, server);
		} else {
			return null;
		}
	}

	/**
	 * Share a page.
	 * 
	 * @param activity
	 *            The parent activity.
	 * @param title
	 *            The page title.
	 * @param url
	 *            The page url.
	 */
	public static void sharePage(Activity activity, String title, String url) {
		Intent shareIntent = new Intent(Intent.ACTION_SEND);

		shareIntent.setType("text/plain");
		shareIntent.putExtra(Intent.EXTRA_TEXT, url);
		shareIntent.putExtra(Intent.EXTRA_SUBJECT, title);

		try {
			activity.startActivity(Intent.createChooser(shareIntent,
					activity.getString(R.string.Main_ShareChooserTitle)));
		} catch (android.content.ActivityNotFoundException ex) {
			// if no app handles it, do nothing
		}
	}

	/**
	 * Display a continue / cancel dialog.
	 * 
	 * @param context
	 *            The current context.
	 * @param icon
	 *            The dialog icon.
	 * @param title
	 *            The dialog title.
	 * @param message
	 *            The dialog message.
	 * @param onContinue
	 *            The dialog listener for the continue button.
	 * @param onCancel
	 *            The dialog listener for the cancel button.
	 */
	public static void showContinueCancelDialog(Context context, int icon,
			String title, String message,
			DialogInterface.OnClickListener onContinue,
			DialogInterface.OnClickListener onCancel) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setCancelable(true);
		builder.setIcon(icon);
		builder.setTitle(title);
		builder.setMessage(message);

		builder.setInverseBackgroundForced(true);
		builder.setPositiveButton(
				context.getResources().getString(R.string.Commons_Continue),
				onContinue);
		builder.setNegativeButton(
				context.getResources().getString(R.string.Commons_Cancel),
				onCancel);
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Show an error dialog.
	 * 
	 * @param context
	 *            The current context.
	 * @param title
	 *            The title string id.
	 * @param message
	 *            The message string id.
	 */
	public static void showErrorDialog(Context context, int title, int message) {
		new AlertDialog.Builder(context).setTitle(title)
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setMessage(message)
				.setPositiveButton(R.string.Commons_Ok, null).show();
	}

	public static void showErrorDialog(Context context, int title,
			String message) {
		new AlertDialog.Builder(context).setTitle(title)
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setMessage(message)
				.setPositiveButton(R.string.Commons_Ok, null).show();
	}

	/**
	 * Display a standard Ok / Cancel dialog.
	 * 
	 * @param context
	 *            The current context.
	 * @param icon
	 *            The dialog icon.
	 * @param title
	 *            The dialog title.
	 * @param message
	 *            The dialog message.
	 * @param onYes
	 *            The dialog listener for the yes button.
	 */
	public static void showOkCancelDialog(Context context, int icon,
			String title, String message, DialogInterface.OnClickListener onYes) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setCancelable(true);
		builder.setIcon(icon);
		builder.setTitle(title);
		builder.setMessage(message);

		builder.setInverseBackgroundForced(true);
		builder.setPositiveButton(
				context.getResources().getString(R.string.Commons_Ok), onYes);
		builder.setNegativeButton(
				context.getResources().getString(R.string.Commons_Cancel),
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Display a standard Ok dialog.
	 * 
	 * @param context
	 *            The current context.
	 * @param icon
	 *            The dialog icon.
	 * @param title
	 *            The dialog title.
	 * @param message
	 *            The dialog message.
	 */
	public static void showOkDialog(Context context, int icon, String title,
			String message) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setCancelable(false);
		builder.setIcon(icon);
		builder.setTitle(title);
		builder.setMessage(message);

		builder.setInverseBackgroundForced(true);
		builder.setPositiveButton(
				context.getResources().getString(R.string.Commons_Ok),
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Display a standard yes / no dialog.
	 * 
	 * @param context
	 *            The current context.
	 * @param icon
	 *            The dialog icon.
	 * @param title
	 *            The dialog title.
	 * @param message
	 *            The dialog message.
	 * @param onYes
	 *            The dialog listener for the yes button.
	 */
	public static void showYesNoDialog(Context context, int icon, int title,
			int message, DialogInterface.OnClickListener onYes) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setCancelable(true);
		builder.setIcon(icon);
		builder.setTitle(context.getResources().getString(title));
		builder.setMessage(context.getResources().getString(message));

		builder.setInverseBackgroundForced(true);
		builder.setPositiveButton(
				context.getResources().getString(R.string.Commons_Yes), onYes);
		builder.setNegativeButton(
				context.getResources().getString(R.string.Commons_No),
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}

}
